package com.sky.wonderrelationship.service.impl;

import com.github.pagehelper.util.StringUtil;
import com.sky.wonderrelationship.entity.Field;
import com.sky.wonderrelationship.entity.FieldShipDetail;
import com.sky.wonderrelationship.entity.FieldShipDetailList;
import com.sky.wonderrelationship.entity.TreeRelationshipsNode;
import com.sky.wonderrelationship.mapper.FieldShipMapper;
import com.sky.wonderrelationship.service.FieldShipService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 功能描述
 *
 * @author: lx
 * @date: 2023年04月14日 14:33
 */
@Service
public class FieldShipServiceImpl implements FieldShipService {
    @Autowired
    FieldShipMapper fieldShipMapper;

    @Override
    public List<Field> getAllFied() {
        return fieldShipMapper.getAllField();
    }

    @Override
    public List<Field> fuzzySearchField(String db, String table, Long field) {
        return fieldShipMapper.fuzzySearchField(db, table, field);
    }

    @Override
    public List<FieldShipDetail> getRelationshipByfieldId(Long field) {
        return fieldShipMapper.getRelationshipByfieldId(field);
    }

    @Override
    public Integer addRelationShipByFieldId(Long field1, Long field2, String note) {
        if (fieldShipMapper.checkShipBy2FieldID(field1, field2).size() != 0) {
            return 0;
        }
        return fieldShipMapper.insertFieldShip(field1, field2, note);
    }

    @Override
    public Integer deleteRelationShipByFieldId(Long id) {
        return fieldShipMapper.deleteFieldShip(id);
    }


    @Override
    public List<FieldShipDetailList> seachSelectShip(String db, String table, Long field) {
        return fieldShipMapper.searchFieldId(db, table, field);
    }

    @Override
    public List<TreeRelationshipsNode> queryTableAndTableShip(Field field1, Field field2) {
        //制造森林的树的root节点
        List<TreeRelationshipsNode> forest = new ArrayList<>();
        //需要一个list保存查出来的子节点，但是子节点如果不符合条件，就不要加进去，不然就成死循环
        //因为是第一层节点，也不用查是否重复出现过   查的也是当前这张表和别的表有多少个关联）（如果有字段的话就限制单个字段和别的表有多少个关联关系）
        List<TreeRelationshipsNode> queryList = fieldShipMapper.queryStartTableShipAllField(field1.getDb(), field1.getTable(), field1.getField());
        for (TreeRelationshipsNode node : queryList) {
            forest.add(node);
            Set<Long> fatherIdSet = new HashSet<>();
            fatherIdSet.add(node.getId());
            if (node.getDb().equals(field2.getDb()) && node.getTable().equals(field2.getTable())) {
              //如果跟要求的表直接符合了，就保存返回了 不继续深挖了
                continue;
            } else {
                node.addChild(buildTreeRelationship(node, field2,fatherIdSet),fatherIdSet);
            }
        }
        return forest;
    }


    /**
     *
     分情况
     1.选择了表查 到另一张表的对应情况
     2.选择了字段查 到另一张表的对应情况
     3.选择了字段 到另一个字段的对应情况
     首先如果是选择了表，那如果当作树来查，那root节点就是null。其下面的节点就到了字段。
     字段信息再去查找所有关联上的其他表的字段

     建造森林的时候要去除循环依赖的情况。每个子节点都要去反查它的祖辈节点是否出现过相同的

     把这东西当作深林来看，先查第一轮，如果限定了field 那就是只有一棵树，如果不限定的话那就有多棵书。
     查询完了再去砍树，把叶子节点没有到达指定表或者字段的节点砍掉
     */
    /*
    * @Description: 递归创造树
    * @author: sky
    * @date: 2023/4/24 15:30
    * @param fatherNode: 父节点
    * @param field: 需要到达的位置bean
    * @param fatherIdSet:  记录父节点出现过的ID用来后续查询，不要出现重复的节点会造成死循环
    * @Return: com.sky.wonderrelationship.entity.TreeRelationshipsNode
    */
    public TreeRelationshipsNode buildTreeRelationship(TreeRelationshipsNode fatherNode, Field field,Set<Long> fatherIdSet) {
        //查询是否有子节点
        List<TreeRelationshipsNode> childTree = null;
        if(fatherIdSet.size() == 1){
            //如果是第一层就照常的去查
            childTree = fieldShipMapper.queryTableShip(fatherNode.getDb(), fatherNode.getTable(), fatherNode.getField());
        } else {
            //其他层要广度优先去查了，所有的字段都要允许才对
            childTree = fieldShipMapper.queryTableShip(fatherNode.getDb(), fatherNode.getTable(), null);
        }
        //为空说明已经到最后一层了，没有子节点了
        if (null == childTree || childTree.size() == 0 || childTree.isEmpty()) {
            return fatherNode;
        }
        for (TreeRelationshipsNode node : childTree) {
            if (fatherNode.addChild(node,fatherIdSet)){
                fatherIdSet.add(node.getId());
                if (node.getDb().equals(field.getDb()) && node.getTable().equals(field.getTable())) {
                    //查到表了，就够了。
                    continue;
                } else {
                    node.addChild(buildTreeRelationship(node, field,fatherIdSet),fatherIdSet);
                }
            }
        }
        return fatherNode;
    }

    @Override
    public List<TreeRelationshipsNode> makeTagForest(List<TreeRelationshipsNode> list, Field field) {
        for (int i = 0; i < list.size(); i++) {
            list.get(i).makeTagInvalidNodes(list.get(i),field,false);
            //森林中的树的叶子节点是空，那就说明这棵树整体都不满足要求，直接砍掉   （主要用来砍掉像时间之类完全无关联的字段）
            if (list.get(i).getTreeRelationshipsNodeList().isEmpty()) {
                if (!list.get(i).isValid(list.get(i), field)) {
                    list.remove(i);
                    i--;
                }
            }
        }
        return list;
    }

    @Override
    public List<String> forestToString(List<TreeRelationshipsNode> list) {
        List<String> paths = new ArrayList<String>();
        if(list.isEmpty()){
            return paths;
        }
        for (TreeRelationshipsNode tree:list){
            if (tree.getValid()){
                paths.addAll(treeToList(tree));
            }
        }
        return paths;
    }

    public List<String> treeToList(TreeRelationshipsNode root) {
        List<String> paths = new ArrayList<>();

        if (root == null) {
            return paths;
        }

        if (root.getTreeRelationshipsNodeList().isEmpty()) {
            paths.add(root.getTable()+"."+root.getField());
            return paths;
        }

        for (TreeRelationshipsNode child : root.getTreeRelationshipsNodeList()) {
            if (child.getValid()) {
                List<String> subPaths = treeToList(child);
                for (String subPath : subPaths) {
                    paths.add(root.getTable() + "." + root.getField() + "->" + subPath);
                }
            }
        }

        return paths;
    }


}
